﻿using Service.Domain.Conventions.User;
using Service.Domain.Interfaces;
using Service.Domain.Interfaces.Repositories;
using Service.Domain.Shared.Models;
using Service.Infrastructure.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Service.Domain.Entities.User
{
    [Serializable]
    public partial class User : IAggregateRoot<UserInfo>
    {
        private UserInfo UserInfo { get; set; }

        private List<UserRole> roles { get; set; }

        private List<Permission> permissions { get; set; }

        public UserInfo Root => this.UserInfo;

        public List<Permission> Permissions => permissions;

        public List<UserRole> Roles => roles;

        readonly IUserRepository userRepository;

        readonly IPermissionRepository permissionRepository;

        readonly IRoleRepository roleRepository;

        public User(IUserRepository userRepository, IPermissionRepository permissionRepository, IRoleRepository roleRepository, UserInfo userInfo)
        {
            this.userRepository = userRepository;
            this.permissionRepository = permissionRepository;
            this.roleRepository = roleRepository;
            this.UserInfo = userInfo;
            this.roles = new List<UserRole>();
            this.permissions = new List<Permission>();
        }

        public async Task GetRoles()
        {
            if (this.UserInfo == null || this.UserInfo.Id == 0) throw new BaseException(ExceptionType.NoUserInfo, "Domain object do not contain user info object.");

            var roles = await this.roleRepository.GetUserRoles(this.UserInfo.Id, new ValidRoleConvention());
            this.roles = roles.ToList();
        }

        public void UpdateStatus(UserStatus status)
        {
            if (this.UserInfo.Status != status)
            {
                this.UserInfo.Status = status;
            }
        }

        public async Task GetPermissionsAsync()
        {
            if (this.Roles == null || this.Roles.Count == 0) return;

            var permissions = await this.permissionRepository.GetUserPermissions(this.Roles.Select(m => m.Id).ToList());

            // 整理为树形结构
            permissions = CombineTree(permissions);

            this.permissions = permissions.ToList();
        }

        public async Task<UserInfo> Login(string userName, string password)
        {
            this.AssertParametersValid(userName, ExceptionType.UserNameRequired, "Username is required");
            this.AssertParametersValid(password, ExceptionType.PasswordRequired, "Password is required");

            var pwdMd5 = password.ToMd5();

            var model = await userRepository.FindByUserNameOrMobileOrEmail(userName, pwdMd5);

            if (model == null) throw new BaseException(ExceptionType.UserNameOrPasswordInvalid, "User name or password invalid");

            this.UserInfo = model;

            return model;
        }

        private IEnumerable<Permission> CombineTree(IEnumerable<Permission> list, int initPid = 0)
        {
            var roots = list.Where(q => q.Pid == initPid).ToList();

            foreach (var item in roots)
            {
                item.Children = CombineTree(list, item.Id);
            }

            return roots;
        }

        private void AssertParametersValid(string value, ExceptionType errorType, string errorMessage)
        {
            if (string.IsNullOrWhiteSpace(value)) throw new BaseException(errorType.ToString(), errorMessage);
        }
    }
}
